package com.example.jmeter.dependent;

import com.example.jmeter.enums.CompressType;
import com.example.jmeter.enums.DependType;
import com.example.jmeter.enums.InstallStage;
import com.example.jmeter.enums.OsType;
import com.example.jmeter.util.FileUtil;
import com.example.jmeter.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.util.Assert;

import java.io.File;
import java.util.List;


/**
 * @program: spring-agent
 * @description:
 * @author: zt22328 赵儒定
 * @create: 2023-04-18 15:05
 **/
@Slf4j
public class SoftDependInstall implements DependInstall {

    protected static final String DEPENDENT = "dependent";

    protected static String DEPENDENT_DIR;

    protected static String DOWNLOAD_DIR;

    protected DependType dependType;

    static {
        String userDir = System.getProperty("user.dir") + File.separator;
        DEPENDENT_DIR = userDir + DEPENDENT;
        DOWNLOAD_DIR = userDir + "download";
    }

    public SoftDependInstall(DependType dependType) {
        this.dependType = dependType;
    }

    @Override
    public boolean installed() {
        return isAvailable();
    }

    @Override
    public void install() {
        // 获取安装进度 0 = 未做任何操作，1 = 文件下载完成，2 = 文件解压完成 3 = 可以正常执行命令
        InstallStage stage = getInstallStage();
        switch(stage) {
            case Completed:
                log.info("{} [{}] already installed!", type(), version());
                break;
            case Decompression:
                log.warn("{} [{}] already decompression, but install fail!", type(), version());
                break;
            case Download:
                log.info("{} [{}] already download, start install ...", type(), version());
                String file = !isLocalInstallPackage() ? DOWNLOAD_DIR + File.separator + fileName()
                        : SoftDependInstall.class.getResource("/").getPath() + DEPENDENT + File.separator +fileName() + downloadSuffix();
                decompression(file);
                break;
            case Native:
                // 目录初始化
                initDir();
                String file2 = !isLocalInstallPackage() ? download()
                        : SoftDependInstall.class.getResource("/").getPath() + DEPENDENT + File.separator +fileName() + downloadSuffix();
                decompression(file2);
                break;
        }
    }

    private InstallStage getInstallStage() {
        if (isAvailable()) {
            return InstallStage.Completed;
        }
        if (isDecompression()) {
            return InstallStage.Decompression;
        }
        String md5key = FileUtil.fileMd5key(downloadPath());
        if (FileUtil.exists(downloadPath()) && dependType.getMd5Key().equals(md5key)) {
            return InstallStage.Download;
        }
        return InstallStage.Native;
    }

    private boolean isDecompression() {
        return new File(executeBinFile()).exists();
    }

    private String downloadPath() {
        return DOWNLOAD_DIR + File.separator + fileName() + downloadSuffix();
    }

    private String download() {
        String file = downloadPath();
        String downloadUrl = getDownloadUrl();
        Assert.hasText(downloadUrl, "安装包下载地址不存在");
        try {
             HttpUtil.httpUrl(downloadUrl, file);
        } catch (Exception e) {
            throw new RuntimeException("文件下载失败！downloadUrl = " + downloadUrl, e);
        }
        if (!FileUtil.exists(file)) {
            throw new RuntimeException("文件下载失败！downloadUrl = " + downloadUrl);
        }
        return file;
    }

    protected String fileName() {
        return type() + "_" + version();
    }

    private void decompression(String path) {
        String suffix = FileUtil.suffix(path);
        CompressType compressType = CompressType.getCompressType(suffix);
        Assert.notNull(compressType, "不支持改类[" + suffix + "]文件解压");
        compressType.decompression(path, DEPENDENT_DIR + File.separator + type(), fileName());
        Assert.isTrue(isAvailable(), "文件解压失败");
    }

    protected boolean isLocalInstallPackage() {
        return false;
    }

    private void initDir() {
        // 安装目录
        val tool = new File(DEPENDENT_DIR + File.separator + type());
        if (!tool.exists()) {
            tool.mkdirs();
        }
        // 下载目录
        val down = new File(DOWNLOAD_DIR);
        if (!down.exists()) {
            down.mkdirs();
        }
    }



    protected boolean isAvailable() {
        // jmeter -v
        try {
            List<String> list = this.execute(dependType.getVersionCmd());
            if (list == null || list.isEmpty()) {
                return false;
            }
            return list.stream().filter(e->e.contains(version())).findFirst().isPresent();
        } catch (Exception ex) {
            log.warn("isAvailable Fail !", ex);
            return false;
        }
    }


    @Override
    public String type() {
        return dependType.name();
    }

    @Override
    public String version() {
        return dependType.getVersion();
    }

    @Override
    public String getDownloadUrl() {
        return dependType.getDownloadUrl();
    }

    public String executeBinFile() {
        return DEPENDENT_DIR + File.separator + type() + File.separator +
                fileName() + File.separator + dependType.getExecuteBin();
    }

    @Override
    public List<String> execute(String cmd, String ... endpoint) {
        return OsType.execute(executeBinFile() + " " + cmd, endpoint);
    }

}
